<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace App\Exception\Handler;

use App\Exception\MessageException;
use App\Model\UserActionsLog;
use App\Utils\FunUtil;
use Hyperf\Context\Context;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\Di\Annotation\Inject;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;

use function Hyperf\Support\env;

class AppExceptionHandler extends ExceptionHandler
{
    #[Inject]
    private ServerRequestInterface $request;

    public function __construct(protected StdoutLoggerInterface $logger)
    {
    }

    public function handle(Throwable $throwable, ResponseInterface $response)
    {
        if ($throwable instanceof MessageException) {
            $status = $throwable->getCode();
            // 格式化输出
            $out = json_encode([
                'code' => $throwable->getCode(),
                'message' => $throwable->getMessage(),
                'data' => $throwable->getData(),
            ], JSON_UNESCAPED_UNICODE);

            // $apiLogId = Context::get('apiLogId');
            // UserActionsLog::query()->where('id', $apiLogId)->update(['response' => $out]);
            // 阻止异常冒泡
            $this->stopPropagation();
        } else {
            $this->logger->error($throwable->getCode());
            $this->logger->error(sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile()));
            $this->logger->error($throwable->getTraceAsString());

            $status = 500;
            $out = [
                'code' => $throwable->getCode(),
                'message' => $throwable->getMessage(),
                'data' => null
            ];

            if (env('APP_ENV', 'dev') == 'dev') {
                $out['debug'] = $throwable->getFile() . '[' . $throwable->getLine() . ']';
                $out['traces'] = $throwable->getTrace();
            }

            $out = json_encode($out, JSON_UNESCAPED_UNICODE);
        }

        $apiLogId = Context::get('apiLogId');
        if (!$apiLogId){
            $params = $this->request->getParsedBody();
            UserActionsLog::query()->insert([
                'uid' => $params['uid'] ?? 0,
                'imei' => $params['imei'] ?? '',
                'ip' => FunUtil::getClientIp(),
                'actions' => $this->request->getUri()->getPath(),
                'params' => json_encode($params),
                'ctime' => time(),
                'response' => $out
            ]);
        }else{
            UserActionsLog::query()->where('id', $apiLogId)->update(['response' => $out]);
        }
        return $response->withHeader('content-type', 'application/json;charset=utf-8')->withStatus($status)->withBody(new SwooleStream($out));
    }

    public function isValid(Throwable $throwable): bool
    {
        return true;
    }
}
